package com.weareint.feigncopy;

import org.apache.commons.collections.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 *
 *
 * <pre>
 *  映射基础接口，不带缓存
 * </pre>
 *
 * @author johnny
 * @date 2021-07-23 1:53 下午
 */
public interface MappingFeignDataService<S, D, T> {

    /**
     * feign 返回的数据
     *
     * @param idList : 需要调用接口的ids
     * @return feign 返回的数据
     */
    List<D> feignData(List<T> idList);

    /**
     * 得到 原始List数据
     *
     * @return 原始数据
     */
    List<S> data();

    /**
     * 选择一个FeignMappingStrategy 默认 AnnotationMappingStrategy
     *
     * @return 默认 AnnotationMappingStrategy
     */
    default FeignMappingStrategy getFeignMappingStrategy() {
        return new AnnotationMappingStrategy();
    }

    /**
     * 得到 当前的FeignMapping注解
     *
     * @return : 当前关心的 FeignMapping
     */
    default List<FeignMapping> getCurrentFeignMapping() {
        List<FeignMapping> feignMappings = new ArrayList<>();
        ParameterizedType p = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class<?> dClass = (Class<?>) p.getActualTypeArguments()[1];
        if (CollectionUtils.isNotEmpty(data())) {
            for (Field field : data().get(0).getClass().getDeclaredFields()) {
                FeignMapping annotation = field.getAnnotation(FeignMapping.class);
                if (annotation != null && annotation.beRelationClass().equals(dClass)) {
                    feignMappings.add(annotation);
                    continue;
                }
            }
        }
        return feignMappings;
    }

    /**
     * 得到 当前的 D 的类型 getSimpleName
     *
     * @return : getSimpleName
     */
    default String getCurrentFeignDataClassType() {
        Type type = this.getClass().getGenericSuperclass();
        ParameterizedType p = (ParameterizedType) type;
        Class<?> dClass = (Class<?>) p.getActualTypeArguments()[1];
        return dClass.getSimpleName();
    }
    /**
     * 获取所有的 ids 通过 data() 根据 FeignMapping 得到 relationIds
     *
     * @return : List<T>
     */
    default List<T> ids() {
        if (CollectionUtils.isEmpty(data())) {
            return null;
        }
        List<T> keys = new ArrayList<>();
        ParameterizedType p = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class<?> dClass = (Class<?>) p.getActualTypeArguments()[1];
        Class<?> tClass = (Class<?>) p.getActualTypeArguments()[2];
        List<FeignMapping> annotations = getCurrentFeignMapping();
        // FeignMapping annotation = getCurrentFeignMapping();
        data().forEach(
                        item -> {
                            for (FeignMapping annotation : annotations) {
                                if (annotation != null
                                        && annotation.beRelationClass().equals(dClass)) {
                                    String relationId = annotation.relationId();
                                    try {
                                        Field relationField =
                                                item.getClass().getDeclaredField(relationId);
                                        relationField.setAccessible(true);
                                        Object o = relationField.get(item);
                                        if (o != null) {
                                            @SuppressWarnings("unchecked")
                                            T t = (T) tClass.cast(o);
                                            keys.add(t);
                                        }
                                    } catch (NoSuchFieldException | IllegalAccessException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        });
        return keys;
    }

    /** 映射，调用 映射器FeignMappingStrategy 去映射 不带缓存 */
    default void mapping() {
        FeignMappingStrategy feignMappingStrategy = getFeignMappingStrategy();
        if (feignMappingStrategy != null) {
            feignMappingStrategy.mapping(data(), feignData(ids()));
        }
    }
}
